package com.starsoft.trade.service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.starsoft.frame.base.bean.BaseFlexsetData;
import com.starsoft.frame.base.service.FlexsetService;
import com.starsoft.frame.util.NumberUtil;
import com.starsoft.frame.util.StringUtil;
import com.starsoft.smdc.bean.SmdcSecurity;
import com.starsoft.smdc.dao.SmdcSecurityDao;
import com.starsoft.trade.bean.TradeBill;
import com.starsoft.trade.bean.TradeFee;
import com.starsoft.trade.dao.TradeFeeDao;
import com.starsoft.trade.util.TradeType;

@Service
public class TradeFeeService{
	
	private static Logger logger = LoggerFactory.getLogger(TradeFeeService.class);
	
	@Autowired
	private TradeFeeDao feeDao;
	
	@Autowired
	private SmdcSecurityDao securityDao;
	
	@Autowired
	private FlexsetService flexsetService;
	
	public void save(TradeFee fee){
		feeDao.saveOrUpdate(fee);
	}
	
	public void delete(TradeFee fee){
		feeDao.delete(fee);
	}
	
	public void deleteAll(Integer acountId){
		feeDao.deleteAll(acountId);
	}
	
	public List<TradeFee> deleteAndCopy(Integer acountFrom, Integer acountTo){
		if(acountFrom.equals(acountTo)){
			throw new RuntimeException("Copy Fee Error: acountFrom is same as acountTo ");
		}
		this.deleteAll(acountTo);
		List<TradeFee> defaultFees = this.getAll(acountFrom);
		for(TradeFee fee : defaultFees){
			feeDao.evict(fee);
			fee.setFeeId(null);
			fee.setAcountId(acountTo);
			this.save(fee);
		}
		return getAll(acountTo);
	}
	
	@SuppressWarnings("unchecked")
	public List<TradeFee> getAll(Integer acountId) {
		List<TradeFee> feeList = feeDao.getFee(acountId);
		Map<String, TradeFee> feeMap = new HashMap<>();
		for (TradeFee tradeFee : feeList) {
			String key = tradeFee.getTradeType() + "," + tradeFee.getExchange();
			feeMap.put(key, tradeFee);
		}

		List<TradeFee> feeResult = new ArrayList<>();
		List<BaseFlexsetData> exchanges = (List<BaseFlexsetData>) flexsetService.getFlexsetValue("SMDC_EXCHANGE");
		List<BaseFlexsetData> tradeTypes = (List<BaseFlexsetData>) flexsetService.getFlexsetValue("TRADE_TYPE");
		for (BaseFlexsetData exchange : exchanges) {
			for (BaseFlexsetData tradeType : tradeTypes) {
				String key = tradeType.getCode() + "," + exchange.getCode();
				if (!feeMap.containsKey(key)) {
					TradeFee tradeFee = new TradeFee();
					tradeFee.setTradeType(tradeType.getCode());
					tradeFee.setExchange(exchange.getCode());
					tradeFee.setAcountId(acountId);
					feeResult.add(tradeFee);
				} else {
					feeResult.add(feeMap.get(key));
					feeList.remove(feeMap.get(key));
				}
			}
		}
		for(TradeFee tradeFee: feeList){
			feeDao.delete(tradeFee);
		}
		return feeResult;
	}
	
	public void setFee(TradeBill bill){
		String exchange = null;		
		TradeType tradeType = TradeType.get(bill);
		if(TradeType.transfer == tradeType || TradeType.oci == tradeType){
			exchange = "ss";
		} else{
			SmdcSecurity security = securityDao.get(bill.getSecId());
			exchange = security.getExchange();
		}		
		TradeFee tradeFee = feeDao.getFee(bill.getAcountId(), bill.getBillType(), exchange);
		if (tradeFee == null) {
			logger.error("no fee config for acount {}, tradeType {}", bill.getAcountId(), TradeType.get(bill));
			return;
		}
		double feeCommision=this.calculateFee(tradeFee.getFeeCommisionBase(), tradeFee.getFeeCommisionRate(),
				tradeFee.getFeeCommisionMin(), tradeFee.getFeeCommisionMax(), bill);
		bill.setFeeCommision(feeCommision);
		double feeTax=this.calculateFee(tradeFee.getFeeTaxBase(), tradeFee.getFeeTaxRate(),
				tradeFee.getFeeTaxMin(), tradeFee.getFeeTaxMax(), bill);
		bill.setFeeTax(feeTax);
		double feeOther=this.calculateFee(tradeFee.getFeeOtherBase(), tradeFee.getFeeOtherRate(),
				tradeFee.getFeeOtherMin(), tradeFee.getFeeOtherMax(), bill);
		bill.setFeeOther(feeOther);
		bill.setFeeAll(feeCommision+feeTax+feeOther);
	}
	
	private double calculateFee(String base, Double rate, Double min, Double max, TradeBill bill){
		double baseNum=bill.getBillTradeMoney();
		if(base!=null && base.contains("Num")){
			baseNum=bill.getSecNum();
		} else if (StringUtil.isEmpty(base)){
			return 0;
		}
		
		double fee=baseNum*NumberUtil.null2Zero(rate)/100;
		if(fee<0)fee=-fee;
		double mind = NumberUtil.null2Zero(min);
		if(mind!=0&&fee<mind) fee=mind;
		double maxd = NumberUtil.null2Zero(max);
		if(maxd!=0&&fee>maxd) fee=maxd;
		return fee;
	}
	
}